package com.leetroll.common.utils;

import com.aliyun.oss.*;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.leetroll.common.constant.AliyunConstant.*;

@Slf4j
@Component
public final class AliyunOSSUtil {

    private static final Long expiration = 3600L * 12;

    private static final OSS commonClient;

    static {
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSupportCname(true);
        commonClient = new OSSClientBuilder().build(CDN_ENDPOINT, ACCESS_KEY, ACCESS_SECRET, conf);
    }

    /**
     * 获取阿里云资源访问url （默认过期时间24小时）
     */
    public static String GetUrl(String bucket, String key) {
        Date expirationDate = new Date(System.currentTimeMillis() + expiration * 1000);
        return commonClient.generatePresignedUrl(bucket, key, expirationDate).toString();
    }

    /**
     * 获取阿里云资源访问url
     *
     * @param expirationYear 过期时间（单位年）
     */
    public static String GetUrl(String key, Integer expirationYear) {
        Date expirationDate = new Date(System.currentTimeMillis() + expirationYear * 60 * 60 * 24 * 365 * 1000L);
        return commonClient.generatePresignedUrl(BUCKET, key, expirationDate).toString();
    }

    /**
     * 上传资源
     */
    public static void upload(String key, InputStream file) {
        OSS client = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_SECRET);
        try {
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET, key, file);
            // 设置存储类型
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            putObjectRequest.setMetadata(metadata);
            // 上传文件
            client.putObject(putObjectRequest);
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        } finally {
            client.shutdown();
        }
    }

    /**
     * 上传ts视频
     */
    public static void uploadTsVideo(String key, InputStream file, String fileFormat) {
        OSS client = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_SECRET);
        try {
            // 设置存储类型
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            if (fileFormat.equals("m3u8")) {
                metadata.setContentType("application/x-mpegurl");
            } else if (fileFormat.equals("ts")) {
                metadata.setContentType("video/mp2t");
                // 设置Object的访问权限为公共读
                metadata.setObjectAcl(CannedAccessControlList.PublicRead);
            }
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET, key, file);
            putObjectRequest.setMetadata(metadata);

            // 上传文件
            client.putObject(putObjectRequest);
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        } finally {
            client.shutdown();
        }
    }

    /**
     * 上传ts视频
     */
    public static void uploadVideo(String key, InputStream file, String fileFormate) {
        OSS client = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_SECRET);
        try {
            // 设置存储类型
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            if (fileFormate.equals("m3u8")) {
                metadata.setContentType("application/x-mpegurl");
            } else if (fileFormate.equals("ts")) {
                metadata.setContentType("video/mp2t");
                // 设置Object的访问权限为公共读
                metadata.setObjectAcl(CannedAccessControlList.PublicRead);
            }
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET, key, file);
            putObjectRequest.setMetadata(metadata);

            // 上传文件
            client.putObject(putObjectRequest);
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        } finally {
            client.shutdown();
        }
    }


    /**
     * 重命名文件
     */
    public static void rename(String source, String dest) {
        try {
            // 拷貝源文件（重命名）
            commonClient.copyObject(BUCKET, source, BUCKET, dest);
            // 删除原文件
            commonClient.deleteObject(BUCKET, source);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        }
    }

    /**
     * 更改文件访问权限
     */
    public static void updateAcl(String key) {
        OSS client = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_SECRET);
        try {
            client.setObjectAcl(BUCKET, key, CannedAccessControlList.PublicRead);
        } catch (OSSException | ClientException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            client.shutdown();
        }
    }

    /**
     * //todo
     * 更改文件contentType
     */
    public static void updatecontentType(String key) {
        OSS client = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_SECRET);
        try {
            // 构造修改后的ObjectMeta。
            ObjectMetadata newMeta = new ObjectMetadata();
            // 设置新的ContentType。
            newMeta.setContentType("video/mp2t");

        } catch (OSSException | ClientException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            client.shutdown();
        }
    }

    /**
     * 删除阿里云目录及目录下的所有文件
     *
     * @param prefix 要删除的目录路径
     */
    public static void deleteFolder(String prefix) {
        if (!prefix.endsWith("/")) return;
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_SECRET);

        try {
            // 列举所有包含指定前缀的文件并删除。
            String nextMarker = null;
            ObjectListing objectListing = null;
            do {
                ListObjectsRequest listObjectsRequest = new ListObjectsRequest(BUCKET)
                        .withPrefix(prefix)
                        .withMarker(nextMarker);

                objectListing = ossClient.listObjects(listObjectsRequest);
                if (objectListing.getObjectSummaries().size() > 0) {
                    List<String> keys = new ArrayList<String>();
                    for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
                        System.out.println("key name: " + s.getKey());
                        keys.add(s.getKey());
                    }
                    DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(BUCKET).withKeys(keys).withEncodingType("url");
                    DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteObjectsRequest);
                    List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
                    try {
                        for (String obj : deletedObjects) {
                            String deleteObj = URLDecoder.decode(obj, "UTF-8");
                            System.out.println(deleteObj);
                        }
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
                nextMarker = objectListing.getNextMarker();
            } while (objectListing.isTruncated());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
